﻿#ifndef CVCALIB3D_H
#define CVCALIB3D_H

#include <opencv2/core.hpp>

class CvCalib3D
{
public:
    CvCalib3D();
    ~CvCalib3D();

    CvCalib3D(cv::Size imageSize, cv::Size boardSize, cv::Size squareSize,
              std::string inputFolder, std::string outputFolder,
              std::string fileNameFormatL, std::string fileNameFormatR);

    /// 获取单个相机的角点数据, 输出到 imagePoints 中, nimages 表示成功识别图的数量
    /// goodImageList 存放可以识别的图
    void getSingleImagePoints(std::vector<std::vector<cv::Point2f> > &imagePoints, int &nimages,
        std::vector<std::string> &imageList, std::vector<std::string> &goodImageList);


    /// 获取左右相机的角点数据, 输出到 imagePoints 中, nimages 表示成功识别图的数量
    /// goodImageList 存放可以识别的图，注意是 2*nimage个图，比如 0, 2, 4 - 左图， 1, 3, 5 - 右图
    void getDualImagePoints(std::vector<std::vector<cv::Point2f> > imagePoints[2], int &nimages,
        std::vector<std::string> &goodImageList);

    /// 双目矫正参数计算，最后输出到 <paramsFileName>.yml/txt文件中
    /// 首先要要通过单目获得两个摄像头的数据
    void stereoCalib(cv::Mat cameraMatrix[2], cv::Mat distCoeffs[2], int &nimages, std::string &paramsFileName);

    /// 双目矫正参数计算，最后输出到 <paramsFileName>.yml/txt文件中
    void stereoCalib(int &nimages, std::string &paramsFileName);

    /// 从文件读取参数，并放入缓存中
    void readParamsFromFiles(std::string filename);

    /// 将角点坐标转成3D坐标, 将结果保存到 outPointsFileName 中
    void verifyImagePointsTo3D(cv::Mat &imageL, cv::Mat &imageR, std::string outPointsFileName, double &err1, double &err2);

    cv::Point3f uv2xyz(cv::Point2f &uvLeft, cv::Point2f &uvRight);
public:
    cv::Size m_imageSize;
    cv::Size m_boardSize;   // 定标板上每行、列的角点数
    cv::Size m_squareSize;  // 实际测量得到的定标板上每个棋盘格的大小

    std::string m_inputFolder;  // 输入文件目录
    std::string m_outputFolder;  // 输出文件目录
    std::string m_fileNameFormatL;
    std::string m_fileNameFormatR;

    cv::FileStorage m_fs;   // 存放参数的文件

    cv::Mat M1;
    cv::Mat D1;
    cv::Mat M2;
    cv::Mat D2;

    cv::Mat R;
    cv::Mat T;
};

#endif // CVCALIB3D_H
